/*=+--+=#=+--     Unmanned Aerial System Management Software      --+=#=+--+=#*\
|          Copyright (C) 2011 Regents of the University of Colorado.           |
|                             All Rights Reserved.                             |

     This program is free software: you can redistribute it and/or modify
     it under the terms of the GNU General Public License version 2 as
     published by the Free Software Foundation.

     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU General Public License for more details.

     You should have received a copy of the GNU General Public License
     along with this program.  If not, see <http://www.gnu.org/licenses/>.

            Jack Elston                       Cory Dixon                        
|           elstonj@colorado.edu              dixonc@colorado.edu              |
|                                                                              |
\*=+--+=#=+--                 --+=#=+--+=#=+--                    --+=#=+--+=#*/

/*!
	\file radarManager.cxx

	\author Cory Dixon
*/
#include <iostream>
#include <fstream>
#include <sstream>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <vector>
#include <string>

#include "level2Layer.h"
#include "clientList.h"
#include "vcgui3.h"
#include "utilities.h"
#include "vcConfig.h"
#include "geoImage.h"

extern "C" {
#include "/usr/local/trmm/GVBOX/include/rsl.h"
}

using namespace std;

/*<---Global Variables---->*/
extern GuiStruct guiStr;

// just an upper bound saftey limit
#define MAX_NUMBER_RADAR_DATA 50  

//---------------------------
// WE use NOAAs radar.weather.gov interface
//---------------------------
#define L2_RADAR_BASE_DIR   VCGUI_DIR"/l2_radar/"
#define L2_RADAR_CACHE_DIR  L2_RADAR_BASE_DIR"data/#S/"
#define L2_RADAR_IMAGE_DIR  L2_RADAR_BASE_DIR"images/#S/"
#define L2_RADAR_CACHE_BASE L2_RADAR_BASE_DIR"images/#S/#S_0.gif"
#define L2_RADAR_CACHE_DIR_LIST  L2_RADAR_BASE_DIR"data/#S/dir.list"

#define L2_RADAR_SITE       "http://mesonet.agron.iastate.edu/data/nexrd2/raw/"
#define L2_RADAR_DATA       L2_RADAR_SITE"#S/"
#define L2_RADAR_DIR_LIST   L2_RADAR_SITE"#S/dir.list"

#define L2_LFTP_RADAR     "lftp -c \"cache off; mirror --delete "L2_RADAR_DATA" "L2_RADAR_CACHE_DIR"\" &"
#define L2_LFTP_RADAR_BASE "lftp -c \"cache off; mirror -i #F -r "L2_RADAR_DATA" "L2_RADAR_CACHE_DIR"\" &"
#define L2_LFTP_RADAR_BASE_DIR  "lftp -c \"cache expire 300; get "L2_RADAR_DIR_LIST" -o "L2_RADAR_CACHE_DIR_LIST"\" "

//---------------------------//
#define URI_MARKER_S    "#S"
#define URI_MARKER_F    "#F"

#define URI_HAS_S    (1 << 0)
//...
#define URI_FLAG_END (1 << 2)
//---------------------------//

Level2Manager::Level2Manager()
{
	radar_list     = NULL;
	site_group     = NULL;
	site_group_h   = NULL;
	img_group      = NULL;
	layerG         = NULL;
	radar_window   = NULL;
	radar_subs     = NULL;
	radar_layer    = NULL;
	tile_queue     = NULL;
	scale_item     = NULL;
	scale_item_h   = NULL;
	active_station = NULL;

	timeScale      = 120.0; // update in radar time in seconds per display update
	time_offset    = 0;   // time off set in minutes for radar

	playing        = false;
}

Level2Manager::~Level2Manager()
{	
	// loop through radar sites
	for(unsigned int ind=0; ind < g_list_length(radar_list); ind++) {
		L2NexradStations_t *station = (L2NexradStations_t *)g_list_nth_data(radar_list,ind);
		if( station ) delete station;
	}
	
	if( radar_list ) g_list_free( radar_list );
	radar_list = 0;

	 for(unsigned int ind=0; ind < g_list_length(radar_subs); ind++) {
		char *uri = (char *)g_list_nth_data(radar_subs,ind);
		if( uri ) g_free(uri);
	}
	if( radar_subs ) g_list_free( radar_subs );
	radar_subs = 0;
}

void Level2Manager::init(GPSMap* map)
{
	LayerManager::init(map);
}

void Level2Manager::one_time_init()
{
	cout << "Initializing IWS Radar : ..............";

	// get my layer group
	layerG = GOO_CANVAS_ITEM(gps_map->getLayerG(GPSMap::LEVEL2_LAYER));
	LayerManager::setShown(true);

	img_group = goo_canvas_group_new (layerG, NULL);
	site_group_h = goo_canvas_group_new (layerG, NULL);

	// add the image to the layer list
	string name = "NEXRAD Sites";
	gps_map->addLayer( name.c_str(), site_group_h, (GooCanvasItem *)GPSMap::LEVEL2_LAYER );
	gps_map->setLayerListShown(site_group_h, true );

	scale_item_h = GOO_CANVAS_ITEM(goo_canvas_group_new (gps_map->getRootItem(), NULL));
	name = "Time Scale";
	gps_map->addLayer( name.c_str(), scale_item_h, (GooCanvasItem *)GPSMap::LEVEL2_LAYER );
	gps_map->setLayerListShown(scale_item_h, true );

	// attempt to get the file attributes, i.e. test file existence
	//int ret;
	struct stat stFileInfo;
	if( stat(L2_RADAR_BASE_DIR, &stFileInfo) != 0 ) {
		cout << "Creating radar directory structure : ";

		if( mkdir(L2_RADAR_BASE_DIR, 0775) < 0 )
			if( errno != EEXIST ) perror("Could not create directory for radar images");
		if( errno == 0 )
			cout << " ....... [done]" << endl;
	}

	// update maps every 5 mins
	g_timeout_add (5*60*1000, Level2Manager::update_web_timeout, this);
	// update time-loop of loading radar files every 10 seconds
	g_timeout_add (10*1000, Level2Manager::update_files_timeout, this);
	// update time-loop of displaying images at 5 Hz
	g_timeout_add (200, Level2Manager::update_image_timeout, this);

	siteFile = guiStr.config.radar_station_file;
	ifstream inputFile(siteFile.c_str(), ios::in);
	if( !inputFile )	{
		cout << "Could not open NexRAD radar file: "  << siteFile <<  endl;
		return ;
	}

	std::string tmpLine;
	std::string x;

	// now start processing, using same line
	while( getline(inputFile, tmpLine ) ) {
		L2NexradStations_t *station = new L2NexradStations_t;
		radar_list = g_list_prepend( radar_list, station);

		x = tmpLine.substr(9,4);
		x.erase(x.find_last_not_of(" \t\n")+1);
		station->icao = x;

		x = tmpLine.substr(20,30);
		x.erase(x.find_last_not_of(" \t\n")+1);
		station->name = x;

		x = tmpLine.substr(72,2);
		station->st = x;

		x = tmpLine.substr(75,30);
		x.erase(x.find_last_not_of(" \t\n")+1);
		station->county = x;

		x = tmpLine.substr(106,9);
		station->lat = atof(x.c_str());

		x = tmpLine.substr(116,10);
		station->lon = atof(x.c_str());

		x = tmpLine.substr(127,6);
		station->elev = atoi(x.c_str());

		x = tmpLine.substr(134,2);
		station->time = atoi(x.c_str());

		//cout << "station: " 
		     //<< " icao=" << station->icao
		     //<< " name=" << station->name
		     //<< " lat=" << station->lat
		     //<< " lon=" << station->lon
			  //<< endl;
			 
	  //cout << "station: " 
			  //<< " icao=" << tmpLine.substr(9,4)
			  //<< " name=" << tmpLine.substr(20,30)
			  //<< " st=" << tmpLine.substr(72,2)
			  //<< " co=" << tmpLine.substr(75,30)
			  //<< " lat=" << tmpLine.substr(106,9)
			  //<< " lon=" << tmpLine.substr(116,10)
			  //<< " elev=" << tmpLine.substr(127,6)
			  //<< " time=" << tmpLine.substr(134,2)
			  //<< endl;

	}
	// close the file
	inputFile.close();

	// reorder list back to that in file
	radar_list = g_list_reverse( radar_list );

	cout << " [done]" << endl;
}


void Level2Manager::updateMap() {};

void Level2Manager::translate_from_zoomChange(double zoom_factor)
{
	double rx, ry, x, y;

	//cout << "RadarManager::translate_from_zoomChange - zoom_factor=" << zoom_factor << " isShown=" << isShown << endl;

	if( !isShown ) return;

	if( site_group_h && !goo_canvas_item_is_visible( site_group_h ) ) {
		if( site_group ) {
			goo_canvas_item_remove(site_group);
			site_group = NULL;
		}
	}

	// loop through radar sites
	for(unsigned int ind=0; ind < g_list_length(radar_list); ind++) {
		// get the site
		L2NexradStations_t *station = (L2NexradStations_t *)g_list_nth_data(radar_list,ind);
		//cout << "station: " << station->name << endl;

		if( site_group ) {
			// set radar range
			g_object_get(G_OBJECT(station->range_item), "radius-x", &rx, "radius-y", &ry, NULL);
			rx *= zoom_factor;
			ry *= zoom_factor;
			g_object_set(G_OBJECT(station->range_item), "radius-x", rx, "radius-y", ry, NULL);

			// transform into window
			y = station->lat;
			x = station->lon;
			gps_map->geoToLayer(GPSMap::LEVEL2_LAYER, x, y);

			// set site location
			g_object_set (G_OBJECT(station->station_item), "x", x, "y", y, NULL);
		}

		// unload cached images
		station->loaded_pix = NULL;
	}
	return;
}

bool Level2Manager::setShown(int setTo)
{
	//cout << "RadarManager::setShown setTo= " << setTo << endl;
	LayerManager::setShown(setTo);

	if(!setTo) {
		//if( site_group_h )
			//g_object_set(site_group_h,"visibility", GOO_CANVAS_ITEM_INVISIBLE, NULL);
		if( scale_item ) 
			goo_canvas_item_remove(scale_item);
		scale_item = NULL;
	}

	if( site_group && !setTo) {
		goo_canvas_item_remove(site_group);
		site_group   = NULL;
	} else if ( setTo && !site_group ) {
		create_canvas();
	}

	return true;
}

void Level2Manager::create_canvas()
{
	double coord_x, coord_y;

	//cout << " RadarManager::create_canvas - site_group= " << site_group << endl;
	
	// see if we are initialized
	if( !layerG ) one_time_init();
	if( site_group ) return;
	site_group = goo_canvas_group_new (site_group_h, NULL);

	// loop through radar sites
	for(unsigned int ind=0; ind < g_list_length(radar_list); ind++) {
		L2NexradStations_t *station = (L2NexradStations_t *)g_list_nth_data(radar_list,ind);

		coord_y = station->lat;
		coord_x = station->lon;

		// transform into window
		gps_map->geoToLayer(GPSMap::LEVEL2_LAYER, coord_x, coord_y);

		double delta_pix = 229648 / gps_map->mPerP( station->lat ); // 124 nautical miles

		station->station_item = goo_canvas_group_new (site_group, 
				"x", coord_x, "y", coord_y, 
				"can-focus", TRUE, 
				NULL);
		setup_item(station->station_item);

		// text - index number
		station->text_item= goo_canvas_text_new (
				station->station_item,
				station->icao.c_str(), 0.0, 0.0, -1,
				GTK_ANCHOR_CENTER,
				"fill_color", "midnight blue",
				"font", "Sans 10px",
				NULL);

		station->range_item = goo_canvas_ellipse_new( 
				station->station_item,
				0.0, 0.0,
				delta_pix, delta_pix,
				"stroke-color-rgba", 0x11111144,
				"fill-color-rgba", 0xFFFF0044,
				"line-width", 2.0,
				"can-focus", TRUE,
				NULL );

		g_signal_connect (station->range_item, "enter-notify-event", G_CALLBACK (on_focus_in), this);
		g_signal_connect (station->range_item, "leave-notify-event", G_CALLBACK (on_focus_out), this);

	}

	// set the layer as active and shown
	gps_map->setLayerListShown( (GooCanvasItem *)GPSMap::LEVEL2_LAYER, true );

	// make sure parent manager layer is shown
	gps_map->toggleLayerShown(GPSMap::LEVEL2_LAYER, true);
}

void Level2Manager::setup_item(GooCanvasItem *item)
{
	g_signal_connect (item, "button-press-event", G_CALLBACK (item_button_press_event_cb), this);
	g_signal_connect (item, "button-release-event", G_CALLBACK (item_button_release_event_cb), this);
	g_signal_connect (item, "key-press-event", G_CALLBACK (item_key_event_cb), this);
	g_signal_connect (item, "key-release-event", G_CALLBACK (item_key_event_cb), this);
	g_signal_connect (item, "motion-notify-event", G_CALLBACK (item_motion_notify_event_cb), this);
}

bool Level2Manager::item_button_press_event_cb (GooCanvasItem *item, GooCanvasItem *target_item, 
		GdkEventButton *event, Level2Manager *me)
{	
	double mouse_x, mouse_y;

	// these are world coordinates
	mouse_x = event->x;
	mouse_y = event->y;

	//printf("RadarManager::item_button_press_event_cb: event->type=%i event->x=%f event->y=%f\n", event->type, event->x, event->y);

	// see if I have a valid pointer
	if( !me ) return false;

	goo_canvas_grab_focus (me->gps_map->getCanvas(), item);

	// find the site the user clicked
	L2NexradStations_t *station = me->findStation( item );
	if( !station )
		return false;

	switch(event->button) {
		case LEFT_MOUSE:
			//cout << "--> " << station->icao << endl;
			break;

		case RIGHT_MOUSE:
			break;

		case MIDDLE_MOUSE:
			me->active_station = station;
			me->create_radar_window( );	
			return true;

		default:
			printf("Unknown mouse button value\n");
			break;
	} 

	// Returning false propagates the event to parent items;
	// returning TRUE ends event propagation. 
	return false;
}

bool Level2Manager::item_key_event_cb (GooCanvasItem  *item, GooCanvasItem  *target_item, 
		GdkEventKey *event, Level2Manager *me)
{
	//printf("RadarManager::item_key_event_cb: event->type=%i event->keyval=%i\n", event->type, event->keyval);
	//fflush(stdout);

	// see if I have a valid pointer
	if( !me ) return false;

	// check for up/down/left/right arrow key press 
	switch (event->keyval)
	{
		case GDK_Up:
			goo_canvas_item_raise(item,NULL);
			break;
		case GDK_Down:
			goo_canvas_item_lower(item,NULL);
			break;   
		default:
			return false; // propogate event 
	} 

	// make sure item is now null, button was released
	return TRUE;
}


bool Level2Manager::item_button_release_event_cb (GooCanvasItem  *item, GooCanvasItem  *target_item, 
		GdkEventButton *event, Level2Manager *me)
{
	//printf("RadarManager::item_button_release_event_cb: event->type=%i event->x=%f event->y=%f\n", event->type, event->x, event->y);
	
	// see if I have a valid pointer
	if( !me ) return false;

	// make sure item is now null, button was released
	return false;
}

bool Level2Manager::item_motion_notify_event_cb (GooCanvasItem  *item, GooCanvasItem  *target_item, 
		GdkEventMotion *event, Level2Manager *me)
{
	//printf("RadarManager::item_motion_event_cb: event->type=%i event->x=%f event->y=%f\n", event->type, event->x, event->y);

	// see if I have a valid pointer
	if( !me ) return false;

	return false;
}


gboolean Level2Manager::update_web_timeout(gpointer data)
{
	//cout << "RadarManager::update_web_timeout" << endl;
	if( !data ) return false;
	Level2Manager *me = (Level2Manager*) data;
	if( !me->radar_subs )
		return true;

	if( !goo_canvas_item_is_visible( me->layerG ) ) 
		return true;

	for(unsigned int ind=0; ind < g_list_length(me->radar_subs); ind++) {
		char *uri = (char *)g_list_nth_data(me->radar_subs,ind);

		if( uri ) {
			//cout << "Updating radar subscription: " << ind << endl << "\t" << uri << endl;
			int ret = system( uri );
			if( ret < 0 ) perror("system command");
		}
		else 
			cout << "!! No URI for subscription: " << ind << endl;
	}
	
	return true;
}

gboolean Level2Manager::update_files_timeout( gpointer data )
{
	if( !data ) return false;
	Level2Manager *radar = (Level2Manager*) data;

	if( goo_canvas_item_is_visible( radar->layerG ) ) 
		radar->update_files();
	return true;
}

void Level2Manager::update_files( )
{
	// loop through stations, and see if we are subscribed
	for(unsigned int ind=0; ind < g_list_length(radar_list); ind++) {

		// get the site
		L2NexradStations_t *station = (L2NexradStations_t *)g_list_nth_data(radar_list,ind);

		if( station->getSubscribed() ) {
			char *uri_dir    = replace_uri(L2_RADAR_CACHE_DIR, station->icao.c_str());
			char *uri_base_f = replace_uri(L2_RADAR_CACHE_BASE, station->icao.c_str());

			//cout << "Looking for maps in: "<< uri << endl;
			//cout << "Looking for maps : "<< station->icao << endl;

			vector<string> files = vector<string>();
			getdir(uri_dir, files);

			// loop through files in directory
			for (unsigned int i = 0; i < files.size();i++) {

				// skip '.' and '..' directories
				if( files[i] == "." || files[i] == ".." )
					continue;

				//cout << "Dir: " << files[i] << endl;
				unsigned int f_ind;
				bool fileFound = false;
				Level2ImgAlloc_t *alloc = NULL;

				//-- look to see if the file is loaded
				for(f_ind=0; f_ind < g_list_length(station->img_alloc_list); f_ind++) {
					// get the file
					alloc = (Level2ImgAlloc_t *)g_list_nth_data(station->img_alloc_list,f_ind);
					if( getFileName(alloc->file.c_str()) == files[i] )
						break;
				}
				if( f_ind < g_list_length(station->img_alloc_list) ) 
					fileFound = true;

				time_t file_tt;
				//-- if this is the base file, it is the same name. So check that the 
				//-- modification time is newer than our current image
				//cout << "checking file times" << endl;
				string f = string(uri_dir) + files[i];
				struct stat attrib;			// create a file attribute structure
				struct tm file_tm;

				// get the attributes of the file
				if( stat(f.c_str(), &attrib) == -1 ) {
					//perror("RadarManager::update_files - stat");
					//printf("Cory needs to write code to remove the reference to a bad file\n");
					continue;
				} 
				file_tt = attrib.st_mtime;	// Get the last modified time and put it into the time structure

				(void)gmtime_r( &file_tt, &file_tm); // convert localtime to UTC
				file_tt = mktime( &file_tm ); // convert broken down time back to time_t
				file_tt -= file_tm.tm_isdst * 3600; // correct for DST

				if( fileFound && !station->getLooped() ) {
					//cout << "file: " << file_tt << " currImg: " << station->currImgTod[type] << endl;
					if( file_tt > station->currImgTod ) {
						//cout << "Refreshing file: " << files[i] << endl;
						alloc->geoImg->Open();
						station->currImgTod = file_tt;
					}
				} 

				//-- did not find file, so load it
				if( !fileFound ) {
					string f = string(uri_dir) + files[i];

					//cout << "\tf=" << f << endl << "\turi_base_f=" << uri_base_f << endl;
					if( (f != uri_base_f && station->getLooped()) || (f == uri_base_f && !station->getLooped()) ) {
						//cout << "Loading file: " << files[i] << endl;
						/*	Level2ImgAlloc_t * imgAlloc = RadarManager::addImage( f );
								if( imgAlloc ) {
								station->img_alloc_list = g_list_append(station->img_alloc_list, imgAlloc);
								if( station->getLooped() ) 
								station->currImgTod = 0;
								else
								station->currImgTod = file_tt;
								} else {
						// remove the bad file
						if( remove( f.c_str() ) < 0 ) {
						cout << "Radar File: " << f << " -- could not remove file" << endl;
						//perror("could not remove file");
						}
						}*/
					}
				}
			}
			g_free(uri_dir);
		} 
	}
}

gboolean Level2Manager::update_image_timeout(gpointer data)
{
	if( !data ) return false;
	Level2Manager * radar = (Level2Manager *)data;
	//if( goo_canvas_item_is_visible( radar->layerG ) ) 
		//radar->update_images();
	return true;
}

void Level2Manager::create_radar_window ()
{
	//cout << "RadarManager::create_radar_window()" << endl;
	if( guiStr.builder == NULL ) {
		cout << "create_param_window() - no builder for gui" << endl;
		return;
	}

	GtkWidget *apply_button = GTK_WIDGET (gtk_builder_get_object (guiStr.builder, "l2applyButton"));
	GtkWidget *cancel_button = GTK_WIDGET (gtk_builder_get_object (guiStr.builder, "l2cancelButton"));

	// create window and setup signals
	if( !radar_window ) {
		radar_window = GTK_WIDGET (gtk_builder_get_object (guiStr.builder, "level2_radar_dialog"));

		// callbacks / signals
		g_signal_connect (GTK_OBJECT(radar_window), "delete_event", G_CALLBACK(radar_window_destroy), radar_window);
		g_signal_connect (GTK_OBJECT(apply_button), "clicked", G_CALLBACK(radar_button_clicked), this);
		g_signal_connect (GTK_OBJECT(cancel_button), "clicked", G_CALLBACK(radar_cancel_clicked), this);
	}

	if( !radar_window || !apply_button || !cancel_button ){
		cout << "Invalid xml ui file for radar" << endl;
		return;
	}

	if( !active_station ) return;

	set_check_butons();

	gtk_window_set_title(GTK_WINDOW(radar_window), active_station->name.c_str());

	gtk_widget_show_all (radar_window);
}


void Level2Manager::radar_cancel_clicked(GtkWidget *w, gpointer user_data)
{
	Level2Manager *me = (Level2Manager *)user_data;
	if( !me ) return;

	// hide the window, it is not destroyed
	gtk_widget_hide(me->radar_window);
}

void Level2Manager::radar_button_clicked(GtkWidget *w, gpointer user_data)
{
	//printf( " -- radar_button_clicked -- \n");

	Level2Manager *me = (Level2Manager *)user_data;
	if( !me ) return;

	bool timeLoop  = 0;

	GtkToggleButton *button;
	if( me->active_station ) {

	//-- time-loop buttons --//
		button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (guiStr.builder, "check_nor"));
		if( gtk_toggle_button_get_active(button) ) {
			if( !gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON (gtk_builder_get_object (guiStr.builder, "l2_snap")) ) )
				timeLoop = true;
		}

		me->subscribeToRadar(timeLoop);
	}

	// hide the window, it is not destroyed
	gtk_widget_hide(me->radar_window);
}

void Level2Manager::set_check_butons()
{
	GtkToggleButton *button;

	button = GTK_TOGGLE_BUTTON (gtk_builder_get_object (guiStr.builder, "check_nor"));
	gtk_toggle_button_set_active(button, active_station->getSubscribed());
}

// If you return false in the "delete_event" signal handler, GTK will emit
// the "destroy" signal. Returning TRUE means you don't want the window to be
// destroyed.  This is useful for popping up 'are you sure you want to quit?'
// type dialogs.
gboolean Level2Manager::radar_window_destroy(GtkWidget * widget, GdkEventKey * event, gpointer user_data)
{
	if( user_data ) {
		gtk_widget_hide_all ( GTK_WIDGET(user_data) );
		return TRUE;
	}
	return false;
}

L2NexradStations_t * Level2Manager::findStation( GooCanvasItem *item )
{
	L2NexradStations_t *station = NULL;
	for(unsigned int ind=0; ind < g_list_length(radar_list); ind++) {
		station = (L2NexradStations_t *)g_list_nth_data(radar_list,ind);
		if(station && station->station_item == item )
			return station;
	}
	return NULL;
}

bool Level2Manager::on_focus_in (GooCanvasItem *item, GooCanvasItem *target, GdkEventFocus *event, gpointer data)
{
	Level2Manager *radar = (Level2Manager *)data;
	if( !radar ) return false;

	goo_canvas_grab_focus (radar->gps_map->getCanvas(), item);
	g_object_set (item, "stroke-color", "black", NULL);

	return false;
}

bool Level2Manager::on_focus_out (GooCanvasItem *item, GooCanvasItem *target, GdkEventFocus *event, gpointer data)
{
	g_object_set (item, "stroke-color-rgba", 0x11111144, NULL);
	return false;
}

void Level2Manager::subscribeToRadar(bool timeLoop )
{
	bool ifNoDelete = false;
	if( !active_station ) return;

		// calculate the uri to download  
		char *uri;
		char *uri_dir = replace_uri(L2_RADAR_CACHE_DIR, active_station->icao.c_str());

		char last[256];
		if( timeLoop ) {
			uri = replace_uri(L2_LFTP_RADAR, active_station->icao.c_str());
		} else {

			//-- get the directory listing
			char *list_uri = replace_uri(L2_LFTP_RADAR_BASE_DIR, active_station->icao.c_str());
			char *list = replace_uri(L2_RADAR_CACHE_DIR_LIST, active_station->icao.c_str());

			int ret;
			struct stat stFileInfo;
			if( stat(list,&stFileInfo) != 0 ) {
				cout << "Download directory list: " << list << endl;
				ret = system( list_uri );
				if( ret < 0 ){
					return;
					perror("system command");
				}
			}

			ifstream inputFile(list, ios::in);
			if( !inputFile )	{
				perror("Could not open file");
				cout << list << endl;
				return;
			}
			char current[256];
			while(inputFile.getline(current,256)){
				String temp(current);
				int space = temp.find(" ")+1;
				strncpy(last,&current[space],256-space);
			}
			inputFile.close();

			//-- clean up
			g_free(list_uri);
			g_free(list);

			//cout << "last file: " << last << endl;

			uri = replace_uri(L2_LFTP_RADAR_BASE, active_station->icao.c_str());
			uri = replace_string(uri, URI_MARKER_F, last);
		}

		//-- remove subscription --//
		if(( active_station->getSubscribed() ) && 
			 ( active_station->getLooped() != timeLoop  )) {
			cout << "Removing subscription to: "<< active_station->icao << ": Level II" << endl;
			active_station->setSubscribed(false);
			
			//-- remove any references to this inactive layers
			if( active_station->img_item_h ) {
				gps_map->delLayer( active_station->img_item_h );
				// unload cached images
				goo_canvas_item_remove( active_station->img_item_h );
				active_station->img_item_h = NULL;
				active_station->img_item   = NULL;
				active_station->loaded_pix = NULL;
			}

			//-- stop and free up the radar web subscription 
			unsigned int ind;
			for(ind=0; ind < g_list_length(radar_subs); ind++) {
				char *l_uri = (char *)g_list_nth_data(radar_subs,ind);
				if( strstr( l_uri, active_station->icao.c_str()) ) {
					radar_subs = g_list_remove(radar_subs, l_uri);
					// free memory
					g_free(l_uri);
					break;
				}
			}
			if( ind == g_list_length(radar_subs) && g_list_length(radar_subs) > 0 )
				cout << "RadarManager::subscribeToRadar -- did not find subscription string in radar_subs" << endl;

			Level2ImgAlloc_t *alloc = NULL;
			unsigned int f_ind=0;
			while( f_ind < g_list_length(active_station->img_alloc_list) ) { // get the file
				alloc = (Level2ImgAlloc_t *)g_list_nth_data(active_station->img_alloc_list,f_ind);
				if( alloc ) {
					if( alloc->file.find( uri_dir ) >= 0 ) {
						//cout << "Unloading file: " << alloc->file << endl;
						active_station->img_alloc_list = g_list_remove(active_station->img_alloc_list, alloc);
						delete alloc;
						alloc = NULL;

					} else
						f_ind++;
				} else {
					// we really should not get here, but if so clean up gracefully
					cout << "!! No img_alloc at location " << f_ind << endl;
				}
			}
		}

		//-- if new subscription --//
		if( !active_station->getSubscribed() ) {
			cout << "Subscribing to: "<< active_station->icao << ": Level II" << endl;
			active_station->setSubscribed(true);
			active_station->setLooped(timeLoop);
			if( timeLoop ) playing = true;

			radar_subs = g_list_append( radar_subs, uri);
			ifNoDelete = true;

			//-- make sure the directory structure exists
			
			string dir = string(L2_RADAR_BASE_DIR);
			//cout << "mkdir - " << dir << endl;
			if( mkdir(dir.c_str(), 0775) < 0 )
				if( errno != EEXIST ) perror("mkdir");

			if( mkdir(L2_RADAR_BASE_DIR"/data", 0775) < 0 )
				if( errno != EEXIST ) perror("Could not create directory for radar data");
			if( mkdir(L2_RADAR_BASE_DIR"/images", 0775) < 0 )
				if( errno != EEXIST ) perror("Could not create directory for radar images");

			//cout << "mkdir - " << uri_dir << endl;
			if( mkdir(uri_dir, 0775) < 0 )
				if( errno != EEXIST ) perror("mkdir");

			//-- create a new image layer for the radar
			if( !active_station->img_layer ) {
				active_station->img_layer = goo_canvas_group_new (img_group, NULL);

				//-- add the image to the layer list
				gps_map->addLayer( active_station->icao.c_str(), active_station->img_layer, 
				               (GooCanvasItem *)GPSMap::LEVEL2_LAYER, active_station->name.c_str() );
				gps_map->setLayerListShown(active_station->img_layer, true );
			}
	
			// make sure the map layer manager is shown
			gps_map->toggleLayerShown( GPSMap::LEVEL2_LAYER, true);

			// attempt to get the file attributes, i.e. test file existence
			//-- get the radar images
			//cout << "Setting up site mirroring : " << endl << "\tURI: " << uri << endl;
			int ret = system( uri );
			if( ret < 0 ) perror("system command");
		}

		if( !ifNoDelete ) g_free(uri);

		if( timeLoop == 0 ) {
			playing = false;
			create_images(uri_dir,last,active_station->icao);
		}

		g_free(uri_dir);

		/*if( active_station->img_layer) {
			gps_map->delLayer( active_station->img_layer );
			goo_canvas_item_remove( active_station->img_layer );
			active_station->img_layer = NULL;
		}*/
}

void Level2Manager::create_images(const char * dir, const char * file, string icao)
{
	cout << "creating image: " << dir << file << endl;
	String path (dir);
	path += String(file);
	
  Radar *radar = NULL;
  radar = RSL_anyformat_to_radar(path.c_str(), icao.c_str());
	if(radar != NULL) {
		RSL_load_refl_color_table();
		RSL_volume_to_gif(radar->v[DZ_INDEX], "dz_sweep", 400, 400, 200.0);
	} else {
		cout << "Level2Manager::create_images : Failed to parse radar data" << endl;
	}
}

char * Level2Manager::replace_uri(const char *uri, const char *site)
{        
	char *url;
	unsigned int i = 1;

	uint32_t uri_format = inspect_map_uri(uri);

	url = g_strdup(uri);
	while (i < URI_FLAG_END)
	{
		char *s;
		char *old;

		old = url;
		switch(i & uri_format)
		{
			case URI_HAS_S:
				s = g_strdup_printf("%s", site);
				url = replace_string(url, URI_MARKER_S, s);
				break;
			default:
				s = NULL;
				break;
		}

		if (s) {
			g_free(s);
			g_free(old);
		}

		i = (i << 1);
	}

	return url;
}

uint32_t Level2Manager::inspect_map_uri(const char *uri)
{
	uint32_t uri_format = 0;
	if (g_strrstr(uri, URI_MARKER_S))
		uri_format |= URI_HAS_S;

	//g_debug("URI Format: 0x%X", uri_format);
	return uri_format;
}
